home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Utilities / Winter Shell 1.0d2 / Source / Libraries / ScrollBarLib / ScrollBarLib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-13  |  8.6 KB  |  338 lines  |  [TEXT/KAHL]

  1. /* Implements a scroll bar. The scroll bar may optionally have an actual
  2.     control associated with it; if no control is present, you can still use
  3.     the scroll bar structure to set and get the minimum and maximum value
  4.     of the control. The application must provide functions to be called
  5.     when the user clicks in the scroll bar. The scroll bar's value may
  6.     range from 0..LONG_MAX. The value is scaled for the scroll bar
  7.     control to fit in the range 0..SHRT_MAX.
  8.     
  9.     94/01/12 aih - added brief comment
  10.     93/12/15 aih - vals are longs, and are scaled to short for ctl if >SHRT_MAX
  11.     93/12/05? aih - added frame library for borders
  12.     93/11/?? aih - added min width and height and resize functions
  13.     93/03/30 aih - created */
  14.  
  15. #include "ControlLib.h"
  16. #include "DrawLib.h"
  17. #include "EventLib.h"
  18. #include "GlobalLib.h"
  19. #include "MathLib.h"
  20. #include "MemoryLib.h"
  21. #include "RectangleLib.h"
  22. #include "ScrollBarLib.h"
  23. #include "WindowLib.h"
  24.  
  25. /* return minimum width for a view with scroll bars */
  26. short SBarMinWidth(Boolean horizontal, Boolean vertical)
  27. {
  28.     return((horizontal ? SBAR_MIN_LENGTH : 0) + (vertical ? SBAR_WIDTH : 0));
  29. }
  30.  
  31. /* return minimum height for a view with scroll bars */
  32. short SBarMinHeight(Boolean horizontal, Boolean vertical)
  33. {
  34.     return((vertical ? SBAR_MIN_LENGTH : 0) + (horizontal ? SBAR_WIDTH : 0));
  35. }
  36.  
  37. /* true if a valid scroll bar */
  38. Boolean SBarValid(ScrollBarHandle sbar)
  39. {
  40.     if (! HandleValidSize(sbar, sizeof(ScrollBarType))) return(false);
  41.     if ((**sbar).ctl && ! CtlValid((**sbar).ctl)) return(false);
  42.     return(true);
  43. }
  44.  
  45. /* allocate a new scroll bar */
  46. ScrollBarHandle SBarBegin(WindowPtr window, const Rect *bounds,
  47.     FrameHandle frame)
  48. {
  49.     volatile ScrollBarHandle sbar = NULL;
  50.     ControlHandle ctl = NULL;
  51.     
  52.     require(WinValid(window));
  53.     require(! bounds || RectValid(bounds));
  54.     require(! frame || FrameValid(frame));
  55.     TRY {
  56.         sbar = HandleBeginClear(sizeof(ScrollBarType));
  57.         (**sbar).window = window;
  58.         (**sbar).frame = frame;
  59.         if (bounds) {
  60.             ctl = NewControl(window, bounds, (StringPtr) "\p",
  61.                              false, 0, 0, 0, scrollBarProc, 0L);
  62.             (**sbar).ctl = ctl;
  63.             FailNIL(ctl);
  64.             SetCRefCon(ctl, (long) sbar);
  65.         }
  66.         if (frame && ctl) {
  67.             if (SBarIsHorizontal(sbar)) {
  68.                 FrameFlagsSet(frame, FrameFlags(frame) | FRAME_HSCROLL);
  69.                 (**frame).bounds.bottom += SBAR_WIDTH - 1;/* program_note: not best place to set this */
  70.             }
  71.             else {
  72.                 FrameFlagsSet(frame, FrameFlags(frame) | FRAME_VSCROLL);
  73.                 (**frame).bounds.right += SBAR_WIDTH - 1;/* program_note: not best place to set this */
  74.             }
  75.         }
  76.         WinRegister(window, sbar, SBarEventTable());
  77.         ensure(SBarValid(sbar));
  78.     } CATCH {
  79.         SBarEnd(sbar);
  80.     } ENDTRY;
  81.     return(sbar);
  82. }
  83.  
  84. /* dispose of the scroll bar */
  85. void SBarEnd(ScrollBarHandle sbar)
  86. {
  87.     if (sbar) {
  88.         WinUnregister((**sbar).window, sbar);
  89.         if ((**sbar).ctl) DisposeControl((**sbar).ctl);
  90.         HandleEnd(sbar);
  91.         sbar = NULL;
  92.     }
  93.     ensure(! SBarValid(sbar));
  94. }
  95.  
  96. /* return handle to scroll bar's control */
  97. ControlHandle SBarCtl(ScrollBarHandle sbar)
  98. {
  99.     require(SBarValid(sbar));
  100.     return((**sbar).ctl);
  101. }
  102.  
  103. /* return current value of scroll bar */
  104. long SBarVal(ScrollBarHandle sbar)
  105. {
  106.     require(SBarValid(sbar));
  107.     return((**sbar).val);
  108. }
  109.  
  110. /* set current value of scroll bar */
  111. void SBarValSet(ScrollBarHandle sbar, long val)
  112. {
  113.     require(SBarValid(sbar));
  114.     require(0 <= val && val <= (**sbar).maxval);
  115.     (**sbar).val = val;
  116.     if ((**sbar).ctl) {
  117.         if ((**sbar).maxval > SHRT_MAX)
  118.             val = (float) (**sbar).val / (**sbar).maxval * SHRT_MAX;
  119.         check(0 <= val && val <= SHRT_MAX);
  120.         SetCtlValue((**sbar).ctl, val);
  121.     }
  122.     ensure(SBarValid(sbar));
  123. }
  124.  
  125. /* return maximum value of scroll bar */
  126. long SBarMax(ScrollBarHandle sbar)
  127. {
  128.     require(SBarValid(sbar));
  129.     return((**sbar).maxval);
  130. }
  131.  
  132. /* set maximum value of scroll bar */
  133. void SBarMaxSet(ScrollBarHandle sbar, long maxval)
  134. {
  135.     require(SBarValid(sbar));
  136.     require(maxval >= 0);
  137.     (**sbar).maxval = maxval;
  138.     if ((**sbar).ctl)
  139.         SetCtlMax((**sbar).ctl, min((**sbar).maxval, SHRT_MAX));
  140.     ensure(SBarValid(sbar));
  141. }
  142.  
  143. /* set data passed to call-back functions */
  144. void SBarDataSet(ScrollBarHandle sbar, void *data)
  145. {
  146.     require(SBarValid(sbar));
  147.     (**sbar).data = data;
  148.     ensure(SBarValid(sbar));
  149. }
  150.  
  151. /* set function called when there's a click in the control */
  152. void SBarActionSet(ScrollBarHandle sbar, void (*action)(void *data, short part))
  153. {
  154.     require(SBarValid(sbar));
  155.     (**sbar).action = action;
  156.     ensure(SBarValid(sbar));
  157. }
  158.  
  159. /* set function called when there's a click in the thumb area */
  160. void SBarThumbSet(ScrollBarHandle sbar, void (*thumb)(void *data, long delta))
  161. {
  162.     require(SBarValid(sbar));
  163.     (**sbar).thumb = thumb;
  164.     ensure(SBarValid(sbar));
  165. }
  166.  
  167. /* true if a horizontal scroll bar */
  168. Boolean SBarIsHorizontal(ScrollBarHandle sbar)
  169. {
  170.     Rect bounds;
  171.     Boolean result = false;
  172.     
  173.     if ((**sbar).ctl) {
  174.         CtlRect((**sbar).ctl, &bounds);
  175.         result = (RectWidth(&bounds) >= RectHeight(&bounds));
  176.     }
  177.     return(result);
  178. }
  179.  
  180. /* true if a vertical scroll bar */
  181. Boolean SBarIsVertical(ScrollBarHandle sbar)
  182. {
  183.     return((**sbar).ctl && ! SBarIsHorizontal(sbar));
  184. }
  185.  
  186. /* resize the scroll bar */
  187. void SBarResize(ScrollBarHandle sbar, short dh, short dv)
  188. {
  189.     Rect bounds;
  190.     GrafPtr port = NULL;
  191.     Rect empty = { 0, 0, 0, 0 };
  192.     RgnHandle clip;
  193.     
  194.     require(SBarValid(sbar));
  195.     if ((**sbar).frame) {
  196.         if ((FrameFlags((**sbar).frame) & FRAME_ANCHOR_RIGHT) == 0) dh = 0;
  197.         if ((FrameFlags((**sbar).frame) & FRAME_ANCHOR_BOTTOM) == 0) dv = 0;
  198.     }
  199.     if ((**sbar).ctl && (dh || dv)) {
  200.         GetPort(&port);
  201.         SetPort(CtlWindow((**sbar).ctl));
  202.         CtlRect((**sbar).ctl, &bounds);
  203.         EraseRect(&bounds);
  204.         InvalRect(&bounds);
  205.         clip = BeginRgn();
  206.         GetClip(clip);
  207.         ClipRect(&empty);
  208.         if (SBarIsVertical(sbar)) {
  209.             check(RectHeight(&bounds) + dv >= SBAR_MIN_LENGTH);
  210.             if (dh) MoveControl((**sbar).ctl, bounds.left + dh, bounds.top);
  211.             if (dv) SizeControl((**sbar).ctl, RectWidth(&bounds), RectHeight(&bounds) + dv);
  212.         }
  213.         else {
  214.             check(SBarIsHorizontal(sbar));
  215.             check(RectWidth(&bounds) + dh >= SBAR_MIN_LENGTH);
  216.             if (dv) MoveControl((**sbar).ctl, bounds.left, bounds.top + dv);
  217.             if (dh) SizeControl((**sbar).ctl, RectWidth(&bounds) + dh, RectHeight(&bounds));
  218.         }
  219.         CtlRect((**sbar).ctl, &bounds);
  220.         InvalRect(&bounds);
  221.         SetClip(clip);
  222.         SetPort(port);
  223.         EndRgn(clip);
  224.     }
  225. }
  226.  
  227. /* activate or deactivate the scroll bar */
  228. void SBarActivate(ScrollBarHandle sbar, Boolean activate)
  229. {
  230.     Rect bounds;
  231.     GrafPtr port = NULL;
  232.     
  233.     require(SBarValid(sbar));
  234.     if ((**sbar).ctl) {
  235.         GetPort(&port);
  236.         SetPort((**sbar).window);
  237.         CtlRect((**sbar).ctl, &bounds);
  238.         if (activate) {
  239.             if (CtlVisible((**sbar).ctl))
  240.                 Draw1Control((**sbar).ctl);
  241.             else
  242.                 ShowControl((**sbar).ctl);
  243.         }
  244.         else {
  245.             if (CtlVisible((**sbar).ctl))
  246.                 HideControl((**sbar).ctl);
  247.             FrameRect(&bounds);
  248.             InsetRect(&bounds, 1, 1);
  249.             EraseRect(&bounds);
  250.         }
  251.         ValidRect(&bounds);
  252.         SetPort(port);
  253.     }
  254.     ensure(SBarValid(sbar));
  255. }
  256.  
  257. /* redraw the scroll bar */
  258. void SBarUpdate(ScrollBarHandle sbar)
  259. {
  260.     Rect bounds;
  261.     GrafPtr port = NULL;
  262.     
  263.     require(SBarValid(sbar));
  264.     if ((**sbar).ctl) {
  265.         if (CtlVisible((**sbar).ctl))
  266.             /* Draw1Control((**sbar).ctl) */; /* update done by UpdtControl */
  267.         else {
  268.             GetPort(&port);
  269.             SetPort((**sbar).window);
  270.             CtlRect((**sbar).ctl, &bounds);
  271.             FrameRect(&bounds);
  272.             InsetRect(&bounds, 1, 1);
  273.             EraseRect(&bounds);
  274.             SetPort(port);
  275.         }
  276.     }
  277.     ensure(SBarValid(sbar));
  278. }
  279.  
  280. /* true if the point is within the scroll bar */
  281. Boolean SBarWithin(ScrollBarHandle sbar, Point where)
  282. {
  283.     require(SBarValid(sbar));
  284.     return((**sbar).ctl && TestControl((**sbar).ctl, where) != 0);
  285. }
  286.  
  287. /* the function passed to TrackControl for clicks not in the thumb */
  288. static pascal void ScrollProc(ControlHandle ctl, short part)
  289. {
  290.     ScrollBarHandle sbar = NULL;
  291.     
  292.     require(CtlValid(ctl));
  293.     if (part) {
  294.         sbar = (ScrollBarHandle) GetCRefCon(ctl);
  295.         check(SBarValid(sbar));
  296.         (**sbar).action((**sbar).data, part);
  297.     }
  298. }
  299.  
  300. /* handle a click in the scroll bar */
  301. void SBarClick(ScrollBarHandle sbar, Point where)
  302. {
  303.     long delta;
  304.     short val;
  305.     
  306.     require(SBarValid(sbar));
  307.     if ((**sbar).ctl) {
  308.         switch (TestControl((**sbar).ctl, where)) {
  309.         case inUpButton:
  310.         case inDownButton:
  311.         case inPageUp:
  312.         case inPageDown:
  313.             TrackControl((**sbar).ctl, where, (ProcPtr) ScrollProc);
  314.             break;
  315.         case inThumb:
  316.             val = GetCtlValue((**sbar).ctl);
  317.             TrackControl((**sbar).ctl, where, (ProcPtr) NULL);
  318.             delta = val - GetCtlValue((**sbar).ctl);
  319.             if ((**sbar).maxval > SHRT_MAX)
  320.                 delta *= (float) (**sbar).maxval / SHRT_MAX;
  321.             (**sbar).thumb((**sbar).data, delta);
  322.             break;
  323.         }
  324.     }
  325.     ensure(SBarValid(sbar));
  326. }
  327.  
  328. /* handle a mouse down event in the scroll bar */
  329. void SBarMouseDown(ScrollBarHandle sbar, EventRecord *event)
  330. {
  331.     Point where = event->where;
  332.  
  333.     require(SBarValid(sbar));
  334.     GlobalToPort(&where, (**sbar).window);
  335.     SBarClick(sbar, where);
  336.     ensure(SBarValid(sbar));
  337. }
  338.